// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_INTERNALS_UI_H_
#define CONTENT_BROWSER_APPCACHE_APPCACHE_INTERNALS_UI_H_

#include <stdint.h>

#include <list>
#include <memory>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "content/browser/appcache/appcache_group.h"
#include "content/browser/appcache/appcache_storage.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_controller.h"
#include "net/base/io_buffer.h"

namespace base {
class ListValue;
class FilePath;
}

namespace content {

// The implementation for the chrome://appcache-internals page.
// This implementation is based on the WebUI API and consists of a controller on
// The UI thread which communicates (through a Proxy) with the AppCacheService
// and AppCache storage which live on the IO thread.
class AppCacheInternalsUI : public WebUIController {
public:
    explicit AppCacheInternalsUI(WebUI* web_ui);
    ~AppCacheInternalsUI() override;

    class Proxy : public AppCacheStorage::Delegate,
                  public base::RefCountedThreadSafe<Proxy> {
    public:
        friend class AppCacheInternalsUI;

        struct ResponseEnquiry {
            std::string manifest_url;
            int64_t group_id;
            int64_t response_id;
        };

    private:
        friend class base::RefCountedThreadSafe<Proxy>;

        Proxy(base::WeakPtr<AppCacheInternalsUI> appcache_internals_ui,
            const base::FilePath& storage_partition);
        ~Proxy() override;

        void RequestAllAppCacheInfo();
        void DeleteAppCache(const std::string& manifest_url);
        void RequestAppCacheDetails(const std::string& manifest_url);
        void RequestFileDetails(const ResponseEnquiry& response_enquiry);
        void HandleFileDetailsRequest();
        void OnAllAppCacheInfoReady(
            scoped_refptr<AppCacheInfoCollection> collection,
            int net_result_code);
        void OnAppCacheInfoDeleted(const std::string& manifest_url,
            int net_result_code);
        void OnGroupLoaded(AppCacheGroup* appcache_group,
            const GURL& manifest_gurl) override;
        void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
            int64_t response_id) override;
        void OnResponseDataReadComplete(
            const ResponseEnquiry& response_enquiry,
            scoped_refptr<AppCacheResponseInfo> response_info,
            std::unique_ptr<AppCacheResponseReader> reader,
            scoped_refptr<net::IOBuffer> response_data,
            int net_result_code);
        void Initialize(
            const scoped_refptr<ChromeAppCacheService>& chrome_appcache_service);
        void Shutdown();

        base::WeakPtr<AppCacheInternalsUI> appcache_internals_ui_;
        base::WeakPtr<AppCacheServiceImpl> appcache_service_;
        base::FilePath partition_path_;
        scoped_refptr<AppCacheStorageReference> disabled_appcache_storage_ref_;
        std::list<ResponseEnquiry> response_enquiries_;
        bool preparing_response_;
        bool shutdown_called_;
    };

    base::WeakPtr<AppCacheInternalsUI> AsWeakPtr()
    {
        return weak_ptr_factory_.GetWeakPtr();
    }

private:
    void CreateProxyForPartition(StoragePartition* storage_partition);
    // Commands from Javascript side.
    void GetAllAppCache(const base::ListValue* args);
    void DeleteAppCache(const base::ListValue* args);
    void GetAppCacheDetails(const base::ListValue* args);
    void GetFileDetails(const base::ListValue* args);

    // Results from commands to be sent to Javascript.
    void OnAllAppCacheInfoReady(scoped_refptr<AppCacheInfoCollection> collection,
        const base::FilePath& partition_path);
    void OnAppCacheInfoDeleted(const base::FilePath& partition_path,
        const std::string& manifest_url,
        bool deleted);
    void OnAppCacheDetailsReady(
        const base::FilePath& partition_path,
        const std::string& manifest_url,
        std::unique_ptr<AppCacheResourceInfoVector> resource_info_vector);
    void OnFileDetailsReady(const Proxy::ResponseEnquiry& response_enquiry,
        scoped_refptr<AppCacheResponseInfo> response_info,
        scoped_refptr<net::IOBuffer> response_data,
        int data_length);
    void OnFileDetailsFailed(const Proxy::ResponseEnquiry& response_enquiry,
        int data_length);

    BrowserContext* browser_context()
    {
        return web_ui()->GetWebContents()->GetBrowserContext();
    }

    Proxy* GetProxyForPartitionPath(const base::FilePath& path);
    std::list<scoped_refptr<Proxy>> appcache_proxies_;
    base::WeakPtrFactory<AppCacheInternalsUI> weak_ptr_factory_;

    DISALLOW_COPY_AND_ASSIGN(AppCacheInternalsUI);
};

} // namespace content
#endif
